﻿using System.Collections;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;

namespace ApplicationFrame.EntityFrameworkCore
{
    /// <summary>
    /// BaseRepository
    /// </summary>
    public abstract class BaseRepository<TEntity, TKey, TDbContext> : QueryRepository<TEntity, TKey, TDbContext> where TDbContext : AbpDbContext<TDbContext> where TEntity : class, IEntity<TKey>
    {
        /// <summary>
        /// ctor
        /// </summary>
        public BaseRepository(IDbContextProvider<TDbContext> dbContextProvider)
            : base(dbContextProvider)
        {
            //DbContextProvider = dbContextProvider;
        }

        ///// <summary>
        ///// DbContext
        ///// </summary>
        //protected IDbContextProvider<TDbContext> DbContextProvider { get; }

        /// <summary>
        /// 新增
        /// </summary>
        public async Task<TEntity> AddAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            var result = await (await GetDbContextAsync()).AddAsync(entity, cancellationToken);
            await SaveChangeAsync(autoSave, cancellationToken);
            return result.Entity;
        }

        /// <summary>
        /// 批量新增
        /// </summary>
        public async Task<bool> BulkAddAsync(IList<TEntity> entityList, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            await (await GetDbContextAsync()).AddRangeAsync(entityList, cancellationToken);
            await SaveChangeAsync(autoSave, cancellationToken);
            return true;
        }

        /// <summary>
        /// 快速批量新增
        /// </summary>
        public virtual Task<bool> FastBulkAddAsync(IList<TEntity> entityList, CancellationToken cancellationToken = default)
        {
            return Task.FromResult(false);
        }

        ///// <summary>
        ///// 删除
        ///// </summary>
        //public async Task<bool> DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
        //{
        //    (await GetDbContextAsync()).Remove(entity);
        //    await SaveChangeAsync(autoSave, cancellationToken);
        //    return await Task.FromResult(true);
        //}

        ///// <summary>
        ///// 删除
        ///// </summary>
        ///// <param name="id">主键id</param>
        //public async Task<bool> DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default)
        //{
        //    var result = await (await GetDbContextAsync()).Set<TEntity>().Where(m => m.Id.Equals(id)).ExecuteDeleteAsync(cancellationToken);
        //    await SaveChangeAsync(autoSave, cancellationToken);
        //    return result > 0;
        //}

        ///// <summary>
        ///// 删除
        ///// </summary>
        //public async Task<bool> DeleteAsync(Expression<Func<TEntity, bool>> condition, bool autoSave = false, CancellationToken cancellationToken = default)
        //{
        //    var result = await (await GetDbContextAsync()).Set<TEntity>().Where(condition).ExecuteDeleteAsync(cancellationToken);
        //    await SaveChangeAsync(autoSave, cancellationToken);
        //    return result > 0;
        //}

        ///// <summary>
        ///// 更新
        ///// </summary>
        //public async Task<TEntity> UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
        //{
        //    var result = (await GetDbContextAsync()).Update(entity);
        //    await SaveChangeAsync(autoSave, cancellationToken);
        //    return await Task.FromResult(result.Entity);
        //}

        /// <summary>
        /// 更新
        /// </summary>
        public async Task<bool> UpdateAsync(Expression<Func<TEntity, bool>> condition, Func<SetPropertyCalls<TEntity>, SetPropertyCalls<TEntity>> updateCall, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            var result = await (await GetDbContextAsync()).Set<TEntity>().Where(condition).ExecuteUpdateAsync(sp => updateCall.Invoke(sp), cancellationToken);
            await SaveChangeAsync(autoSave, cancellationToken);
            return result > 0;
        }

        #region private methods
        /// <summary>
        /// 判断是否开启事务，未开启直接提交数据库
        /// </summary>
        private async Task SaveChangeAsync(bool autoSave, CancellationToken cancellationToken)
        {
            if (autoSave)
                await (await GetDbContextAsync()).SaveChangesAsync(cancellationToken);
        }
        #endregion
    }

    /// <summary>
    /// QueryRepository
    /// </summary>
    public abstract class QueryRepository<TEntity, TKey, TDbContext> : EfCoreRepository<TDbContext, TEntity, TKey>, IQueryable<TEntity>, IEnumerable<TEntity>, IAsyncEnumerable<TEntity> where TDbContext : AbpDbContext<TDbContext> where TEntity : class, IEntity<TKey>
    {
        /// <summary>
        /// ctor
        /// </summary>
        public QueryRepository(IDbContextProvider<TDbContext> dbContextProvider) : base(dbContextProvider)
        {
        }

        /// <summary>
        /// Type
        /// </summary>
#pragma warning disable CS0618 // 类型或成员已过时
        public Type ElementType => GetQueryable().ElementType;
#pragma warning restore CS0618 // 类型或成员已过时

        /// <summary>
        /// Expression
        /// </summary>
#pragma warning disable CS0618 // 类型或成员已过时
        public Expression Expression => GetQueryable().Expression;
#pragma warning restore CS0618 // 类型或成员已过时

        /// <summary>
        /// IQueryProvider
        /// </summary>
#pragma warning disable CS0618 // 类型或成员已过时
        public IQueryProvider Provider => GetQueryable().Provider;
#pragma warning restore CS0618 // 类型或成员已过时

        /// <summary>
        /// IAsyncEnumerator
        /// </summary>
        public IAsyncEnumerator<TEntity> GetAsyncEnumerator(CancellationToken cancellationToken = default)
        {
#pragma warning disable CS0618 // 类型或成员已过时
            return GetQueryable().AsAsyncEnumerable().GetAsyncEnumerator();
#pragma warning restore CS0618 // 类型或成员已过时
        }

        /// <summary>
        /// IEnumerator
        /// </summary>
        public IEnumerator<TEntity> GetEnumerator()
        {
#pragma warning disable CS0618 // 类型或成员已过时
            return GetQueryable().GetEnumerator();
#pragma warning restore CS0618 // 类型或成员已过时
        }

        /// <summary>
        /// IEnumerator
        /// </summary>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #region private methods

        ///// <summary>
        ///// IQueryable
        ///// </summary>
        //private IQueryable<TEntity> GetQueryable()
        //{
        //    return GetDbContextAsync().Result.Set<TEntity>().AsQueryable<TEntity>();
        //}

        #endregion
    }

    /// <summary>
    /// UlongBaseRepository,主键ulong
    /// </summary>
    public abstract class UlongBaseRepository<TEntity, TDbContext> : BaseRepository<TEntity, ulong, TDbContext> where TEntity : class, IEntity<ulong> where TDbContext : AbpDbContext<TDbContext>
    {
        /// <summary>
        /// UlongBaseRepository
        /// </summary>
        protected UlongBaseRepository(IDbContextProvider<TDbContext> dbContextProvider)
            : base(dbContextProvider)
        {
        }
    }

    /// <summary>
    /// LongBaseRepository,主键long
    /// </summary>
    public abstract class LongBaseRepository<TEntity, TDbContext> : BaseRepository<TEntity, long, TDbContext> where TEntity : class, IEntity<long> where TDbContext : AbpDbContext<TDbContext>
    {
        /// <summary>
        /// LongBaseRepository
        /// </summary>
        protected LongBaseRepository(IDbContextProvider<TDbContext> dbContextProvider)
            : base(dbContextProvider)
        {
        }
    }

    /// <summary>
    /// StringBaseRepository,主键string
    /// </summary>
    public abstract class StringBaseRepository<TEntity, TDbContext> : BaseRepository<TEntity, string, TDbContext> where TEntity : class, IEntity<string> where TDbContext : AbpDbContext<TDbContext>
    {
        /// <summary>
        /// StringBaseRepository
        /// </summary>
        protected StringBaseRepository(IDbContextProvider<TDbContext> dbContextProvider)
            : base(dbContextProvider)
        {
        }
    }

    /// <summary>
    /// GuidBaseRepository,主键guid
    /// </summary>
    public abstract class GuidBaseRepository<TEntity, TDbContext> : BaseRepository<TEntity, Guid, TDbContext> where TEntity : class, IEntity<Guid> where TDbContext : AbpDbContext<TDbContext>
    {
        /// <summary>
        /// GuidBaseRepository
        /// </summary>
        protected GuidBaseRepository(IDbContextProvider<TDbContext> dbContextProvider)
            : base(dbContextProvider)
        {
        }
    }
}
